package com.ruicar.afs.cloud.admin.gwmgc.sso.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.admin.entity.SysDepartment;
import com.ruicar.afs.cloud.admin.entity.SysUser;
import com.ruicar.afs.cloud.admin.gwmgc.sso.config.GwmfcSsoProperties;
import com.ruicar.afs.cloud.admin.gwmgc.sso.dto.SsoRequestDto;
import com.ruicar.afs.cloud.admin.gwmgc.sso.dto.SsoResponseDto;
import com.ruicar.afs.cloud.admin.gwmgc.sso.dto.SsoResponse;
import com.ruicar.afs.cloud.admin.gwmgc.sso.dto.SsoUserDto;
import com.ruicar.afs.cloud.admin.gwmgc.sso.service.SsoService;
import com.ruicar.afs.cloud.admin.service.SysDepartmentService;
import com.ruicar.afs.cloud.admin.service.SysUserService;
import com.ruicar.afs.cloud.common.core.constant.CommonConstants;
import com.ruicar.afs.cloud.common.core.holder.TransRequestContextHolder;
import com.ruicar.afs.cloud.common.core.security.feign.Oauth2OperationService;
import com.ruicar.afs.cloud.common.core.security.service.AfsNoPassLoginService;
import com.ruicar.afs.cloud.common.core.util.Base64Util;
import com.ruicar.afs.cloud.common.core.util.ClientTypeUtil;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@AllArgsConstructor
@Slf4j
public class SsoServiceImpl implements SsoService {
    private final Oauth2OperationService oauth2OperationService;
    private final AfsNoPassLoginService afsNoPassLoginService;
    private final SysUserService userService;
    private final GwmfcSsoProperties gwmfcSsoProperties;
    private final SysDepartmentService sysDepartmentService;
    private static final String SUCCESS_CODE="200";
    private static final String ERROR_CODE="500";
    @Override
    public SsoResponseDto validate(SsoRequestDto ssoRequestDto) {
        SsoResponseDto ssoResponseDto = new SsoResponseDto();
        try {
            String token =  remoteValidateToken(ssoRequestDto.getToken());
            Assert.isTrue(token!=null,"token校验失败");
            TokenInfo tokenInfo = decodeToken(token);
            Assert.isTrue(tokenInfo!=null,"token解析失败");
            String userLoginName = tokenInfo.getUserName();
            if (StringUtils.isEmpty(userLoginName)) {
                ssoResponseDto.setValidate(false);
                return ssoResponseDto;
            }
            ssoResponseDto.setSsoToken(token);
            //token校验通过 执行更新最后一次登录时间及密码修改时间
            updateUser(userLoginName);
            //构建 http请求参数
            Map<String, String> requestParam = new HashMap<>(8);
            requestParam.put(CommonConstants.GRANT_TYPE, "password");
            //用户名为前缀+系统登录名
            requestParam.put(CommonConstants.USERNAME, CommonConstants.WITH_OUT_PASS_PREFIX + userLoginName);
            //密码填系统默认密码
            requestParam.put(CommonConstants.PASSWORD, CommonConstants.DEFAULT_PASS);
            requestParam.put(CommonConstants.TENANT_ID, CommonConstants.DEVICE_ID);
            requestParam.put(CommonConstants.SSO, CommonConstants.COMMON_FLAG_TRUE);
            //填充一次性校验码，使用过后不能再次使用,校验码有效期为 120s
            requestParam.put(CommonConstants.NO_PASS_LOGIN, afsNoPassLoginService.getCheckCode());
            //构建 http请求头
            Map<String, String> requestHeader = new HashMap<>(8);
            ClientTypeUtil.ClientTypeEnum clientTypeEnum = TransRequestContextHolder.getClientInfo().getClientType();
            requestHeader.put(CommonConstants.AUTHORIZATION, "Basic " + Base64Util.encode((clientTypeEnum.getClientId() + ":" + clientTypeEnum.getClientSecret()).getBytes()));
            Object object = oauth2OperationService.login(requestParam, requestHeader);
            if (object instanceof IResponse) {
                ssoResponseDto.setValidate(false);
            } else {
                ssoResponseDto.setValidate(true);
                ssoResponseDto.setToken(object);
                ssoResponseDto.setTokenExpireTime(tokenInfo.getExtDate());
            }
        }catch (Exception e){
            log.error("",e);
            ssoResponseDto.setValidate(false);
        }
        return ssoResponseDto;
    }

    private void updateUser(String userName){
        SysUser sysUser = userService.getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername,userName),false);
        if(sysUser!=null){
            sysUser.setLastLoginFailTime(0L);
            sysUser.setLastPassChangeTime(System.currentTimeMillis());
            sysUser.setPassErrorCount(0);
            userService.updateById(sysUser);
        }
    }

    private boolean validateTokenLocal(String token, String exceptSubject){
        TokenInfo tokenInfo  = decodeToken(token);
        if(tokenInfo==null){
            return false;
        }
        return StringUtils.equals(tokenInfo.getUserName(),exceptSubject);
    }

    @Override
    public String addUser(SsoUserDto ssoUserDto, String token) {
        SsoResponse ssoResponse = new SsoResponse();
        ssoResponse.setCode(SUCCESS_CODE);
        ssoResponse.setMsg("");
        String ssoToken =  remoteValidateToken(token);
        Assert.isTrue(ssoToken!=null,"token校验失败");
//        if(!validateTokenLocal(ssoToken,"admin")){
//            ssoResponse.setCode(ERROR_CODE);
//            ssoResponse.setMsg("token校验失败");
//            return JSON.toJSONString(ssoResponse);
//        }
        List<SysUser> sysUserList = userService.list(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, ssoUserDto.getUserName()));
        if(CollectionUtil.isEmpty(sysUserList)){
            SysUser sysUser = new SysUser();
            sysUser.setPassword(SysUserService.ENCODER.encode(ssoUserDto.getPassword()));
            sysUser.setUsername(ssoUserDto.getUserName());
            sysUser.setUserRealName(ssoUserDto.getUserName());
            sysUser.setTenantId(null);
            sysUser.setUserEmail(ssoUserDto.getEmail());
            List<SysDepartment> sysDepartmentList= sysDepartmentService.list(Wrappers.<SysDepartment>lambdaQuery().eq(SysDepartment::getParentId,CommonConstants.PARENT_ID).orderByAsc(SysDepartment::getId));
            if(CollectionUtil.isEmpty(sysDepartmentList)){
                ssoResponse.setCode(ERROR_CODE);
                ssoResponse.setMsg("业务系统，部门为空不能添加用户");
                return JSON.toJSONString(ssoResponse);
            }
            sysUser.setDeptId(sysDepartmentList.get(0).getId());
            sysUser.setLastLoginFailTime(0L);
            sysUser.setLastPassChangeTime(System.currentTimeMillis());
            sysUser.setPassErrorCount(0);
            if (!userService.save(sysUser)) {
                ssoResponse.setCode(ERROR_CODE);
                ssoResponse.setMsg("用户添加失败");
                return JSON.toJSONString(ssoResponse);
            }else {
                ssoResponse.setMsg("success");
            }
        }else{
            ssoResponse.setCode(SUCCESS_CODE);
            ssoResponse.setMsg("用户已存在");
            updateUser(ssoUserDto.getUserName());
        }
        return JSON.toJSONString(ssoResponse);
    }

    @Override
    public String userDisable(SsoUserDto ssoUserDto, String token) {
        SsoResponse ssoResponse = new SsoResponse();
        ssoResponse.setCode(SUCCESS_CODE);
        ssoResponse.setMsg("");
        String ssoToken =  remoteValidateToken(token);
        Assert.isTrue(ssoToken!=null,"token校验失败");
//        if(!validateTokenLocal(ssoToken,"admin")){
//            ssoResponse.setCode(ERROR_CODE);
//            ssoResponse.setMsg("token校验失败");
//            return JSON.toJSONString(ssoResponse);
//        }
        List<SysUser> sysUserList = userService.list(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, ssoUserDto.getUserName()));
        if(CollectionUtil.isEmpty(sysUserList)){
            ssoResponse.setCode(ERROR_CODE);
            ssoResponse.setMsg("业务系统不存在对应有效账户");
            return JSON.toJSONString(ssoResponse);
        }else{
            if(userService.removeById(Long.valueOf(sysUserList.get(0).getUserId()))) {
                ssoResponse.setCode(SUCCESS_CODE);
                ssoResponse.setMsg("");
            }else {
                ssoResponse.setCode(ERROR_CODE);
                ssoResponse.setMsg("用户删除失败");
            }
        }
        return JSON.toJSONString(ssoResponse);
    }


    private String remoteValidateToken(String token){
        HttpResponse httpResponse = HttpUtil.createGet(gwmfcSsoProperties.getUrl()+"/api/verify").header("token",token).execute();
        try {
            if (httpResponse.getStatus() == 200) {
                JSONObject jsonObject = JSON.parseObject(httpResponse.body());
                if (jsonObject.containsKey("code") && StringUtils.equals(SUCCESS_CODE, jsonObject.getString("code"))) {
                   return jsonObject.getJSONObject("data").getString("token");
                } else {
                    log.info("接口校验失败,接口返回{}",jsonObject.toJSONString());
                    return null;
                }
            } else {
                return null;
            }
        }catch (Exception e){
            log.error("",e);
            return null;
        }
    }

    private TokenInfo decodeToken(String token){
        Assert.isTrue(StringUtils.isNotEmpty(token),"传入token为空");
        String [] tokens = StringUtils.split(token,".");
        Assert.isTrue(tokens.length==3,"token不规范");
        JSONObject jsonObject = JSON.parseObject(Base64Util.decode(tokens[1]),JSONObject.class);
        TokenInfo tokenInfo = new TokenInfo();
        tokenInfo.setUserName(jsonObject.getString("sub"));
        tokenInfo.setExtDate(jsonObject.getLong("exp")*1000);
        return tokenInfo;
    }

    @Override
    public SsoResponseDto refreshToken(SsoRequestDto ssoRequestDto) {
        SsoResponseDto ssoResponseDto = new SsoResponseDto();
        HttpResponse httpResponse = HttpUtil.createGet(gwmfcSsoProperties.getUrl()+"/api/verify").header("token",ssoRequestDto.getToken()).execute();
        try {
            if (httpResponse.getStatus() == 200) {
                JSONObject jsonObject = JSON.parseObject(httpResponse.body());
                if (jsonObject.containsKey("code") && StringUtils.equals(SUCCESS_CODE, jsonObject.getString("code"))) {
                    ssoResponseDto.setValidate(true);
                    ssoResponseDto.setToken(jsonObject.getJSONObject("data").getString("token"));
                    TokenInfo tokenInfo = decodeToken(jsonObject.getJSONObject("data").getString("token"));
                    Assert.isTrue(tokenInfo!=null,"token解析失败");
                    ssoResponseDto.setTokenExpireTime(tokenInfo.getExtDate());
                } else {
                    ssoResponseDto.setValidate(false);
                }
            } else {
                ssoResponseDto.setValidate(false);
            }
        }catch (Exception e){
            log.error("",e);
            ssoResponseDto.setValidate(false);
        }
        return ssoResponseDto;
    }
    @Data
    private static class TokenInfo{
        String userName;
        long extDate;
    }
}
